import type { NamePath } from 'ant-design-vue/es/form/interface'
import type { VueKey, VueNode, VueText } from '#/types'
import type { FormInstance, FormItemProps } from 'ant-design-vue'
import type {
  ProFieldValueType,
  ProFieldValueTypeWithFieldProps,
  ValueTypeWithFieldProps
} from './types'
import type { ProSchemaValueEnumMap, ProSchemaValueEnumObj } from '#/provider'
import type { LabelTooltipType } from '#/table/typing'

export type PageInfo = {
  pageSize: number
  total: number
  current: number
}

export type { ProFieldValueType, ProFieldValueTypeWithFieldProps }

export type RequestOptionsType = {
  label?: VueNode
  value?: VueText
  /** 渲染的节点类型 */
  optionType?: 'optGroup' | 'option'
  options?: Omit<RequestOptionsType, 'children' | 'optionType'>[]
  [key: string]: any
}

export type ProFieldRequestData<U = any> = (params: U, props: any) => Promise<RequestOptionsType[]>

export type ProFieldTextType = VueNode | VueNode[] | Record<string, any> | Record<string, any>[]

export type SearchTransformKeyFn = (
  value: any,
  namePath: string,
  allValues: any
) => string | Record<string, any>

export type SearchConvertKeyFn = (value: any, field: NamePath) => string | Record<string, any>

export type ProTableEditableFnType<T> = (value: any, record: T, index: number) => boolean

// 支持的变形，还未完全支持完毕
/** 支持的变形，还未完全支持完毕 */
export type ProSchemaComponentTypes =
  | 'form'
  | 'list'
  | 'descriptions'
  | 'table'
  | 'cardList'
  | undefined

/** 操作类型 */
// eslint-disable-next-line @typescript-eslint/ban-types
export type ProCoreActionType<T = {}> = {
  /** @name 刷新 */
  reload: (resetPageIndex?: boolean) => Promise<void>
  /** @name 刷新并清空，只清空页面，不包括表单 */
  reloadAndRest?: () => Promise<void>
  /** @name 重置任何输入项，包括表单 */
  reset?: () => void
  /** @name 清空选择 */
  clearSelected?: () => void
  /** @name p页面的信息都在里面 */
  pageInfo?: PageInfo
} & T

/** 各个组件公共支持的 render */
export type ProSchema<
  Entity = Record<string, any>,
  ExtraProps = unknown,
  ComponentsType = ProSchemaComponentTypes,
  ValueType = 'text',
  ExtraFormItemProps = unknown
> = {
  /** @name 确定这个列的唯一值,一般用于 dataIndex 重复的情况 */
  key?: VueKey
  /**
   * 支持一个数字，[a,b] 会转化为 obj.a.b
   *
   * @name 与实体映射的key
   */
  dataIndex?: string | number | (string | number)[]

  /**
   * 支持 ReactNode 和 方法
   *
   * @name 标题
   */
  title?:
    | ((schema: ProSchema<Entity, ExtraProps>, type: ComponentsType, dom: VueNode) => VueNode)
    | VueNode

  /** @name 展示一个 icon，hover 是展示一些提示信息 */
  tooltip?: LabelTooltipType | string

  /** @deprecated 你可以使用 tooltip，这个更改是为了与 antd 统一 */
  tip?: string

  /**
   * 支持 object 和Map，Map 是支持其他基础类型作为 key
   *
   * @name 映射值的类型
   */
  valueEnum?:
    | ((row: Entity) => ProSchemaValueEnumObj | ProSchemaValueEnumMap)
    | ProSchemaValueEnumObj
    | ProSchemaValueEnumMap

  /**
   * @name 自定义的 formItemProps
   */
  formItemProps?:
    | (FormItemProps & ExtraFormItemProps)
    | ((
        form: FormInstance,
        config: ProSchema<Entity, ExtraProps> & {
          type: ComponentsType
          isEditable?: boolean
          rowKey?: string
          rowIndex: number
          entity: Entity
        }
      ) => FormItemProps & ExtraFormItemProps)

  /**
   * 修改的数据是会被 valueType 消费
   *
   * @name 自定义 render 内容
   */
  renderText?: (text: any, record: Entity, index: number, action: ProCoreActionType) => any
  /**
   * Render 方法只管理的只读模式，编辑模式需要使用 renderFormItem
   *
   * @name 自定义只读模式的dom
   */
  render?: (
    dom: VueNode,
    entity: Entity,
    index: number,
    action: ProCoreActionType | undefined,
    schema: ProSchema<Entity, ExtraProps, ComponentsType, ValueType> & {
      isEditable?: boolean
      type: ComponentsType
    }
  ) =>
    | VueNode
    | {
        children: VueNode
        props: any
      }

  /**
   * 返回一个 ReactNode，会自动包裹 value 和 onChange
   *
   * @name 自定义编辑模式
   */
  renderFormItem?: (
    schema: ProSchema<Entity, ExtraProps, ComponentsType, ValueType> & {
      isEditable?: boolean
      index?: number
      type: ComponentsType
      originProps?: any
    },
    config: {
      onSelect?: (value: any) => void
      onChange?: <T = any>(value: T) => void
      value?: any
      type: ComponentsType
      recordKey?: VueKey | VueKey[]
      record?: Entity
      isEditable?: boolean
      defaultRender: (
        newItem: ProSchema<Entity, ExtraProps, ComponentsType, ValueType>
      ) => JSX.Element | null
    },
    form: FormInstance,
    action?: any
    // action?: Omit<
    //   UseEditableUtilType,
    //   'newLineRecord' | 'editableKeys' | 'actionRender' | 'setEditableRowKeys'
    // >
  ) => VueNode

  /**
   *  @name 可编辑表格是否可编辑
   *
   * @example 不允许编辑
   * editable=false
   *
   * @example 如果id=1不允许编辑
   * editable={(value,row,index)=> row.id !==1 }
   */
  editable?: false | ProTableEditableFnType<Entity>

  /** @name 从服务器请求枚举 */
  request?: ProFieldRequestData
  /** @name request防抖动时间 默认10 单位ms */
  debounceTime?: number
  /** @name 从服务器请求的参数，改变了会触发 reload */
  params?:
    | ((record: Entity, column: ProSchema<Entity, ExtraProps>) => Record<string, any>)
    | Record<string, any>
  /** @name 依赖字段的name，暂时只在拥有 request 的项目中生效，会自动注入到 params 中 */
  dependencies?: NamePath[]

  /** @name 在 descriptions 隐藏 */
  hideInDescriptions?: boolean
  /** @name 在 Form 中隐藏 */
  hideInForm?: boolean
  /** @name 在 table 中隐藏 */
  hideInTable?: boolean
  /** @name 在 table的查询表单 中隐藏 */
  hideInSearch?: boolean
  /** 设置到 ProField 上面的 Props，内部属性 */
  proFieldProps?: ProFieldProps
} & ExtraProps &
  ValueTypeWithFieldProps<Entity, ComponentsType, ExtraProps, ValueType>

export interface ProFieldProps {
  light?: boolean
  emptyText?: VueNode
  label?: VueNode
  mode?: 'read' | 'edit'
  /** 这个属性可以设置useSwr的key */
  proFieldKey?: string
  render?: any
  readonly?: boolean
}
